package com.cj.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cj.entity.News;
import com.cj.mapper.NewsMapper;

import cn.hutool.core.date.DateUtil;

@Controller
public class HNewsController {
	
	@Autowired
	RedisTemplate<String, String> redisTemplate;
	
	@Autowired
	NewsMapper newsMapper;
	
	TimeUnit time = null;
	
	
	
	@RequestMapping("/getHNews/{value}")
	public String getHNews(@PathVariable("value") Long id,HttpServletRequest request,Model model) {
		if(id == null || id < 101) {
			model.addAttribute("message","错误的参数");
			return "HNews";
		}
		HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
		String json;
		String newsKey_prefix = "hnews";//新闻key的前缀
		String newsKey = newsKey_prefix + id;//拼凑成 一个完整的新闻key
		Map<String, Object> entries = opsForHash.entries(newsKey); //从redis取 ,注意此时 是hash类型
		if(entries == null || entries.size()<=0) {//如果木有取到
			Map<String,Object> map = new HashMap<String,Object>();
			map.put("news_id", id);
			List<News> newList = newsMapper.selectByMap(map); //从数据库中获取
			if(newList == null || newList.size() <= 0) {//数据库里也没取到 这里要加2分
				model.addAttribute("message","数据库里没有取到");
				return "HNews";
				//这里加入  防穿透 代码，为了代码 演示 清晰，这里暂时不加了,假设 都能取到数据
			}
			Map<String,Object> DBMap = new HashMap<String, Object>();
			DBMap.put("news_id", Long.toString(newList.get(0).getNewsId()));
			DBMap.put("news_title", newList.get(0).getNewsTitle());
			DBMap.put("views", Long.toString(newList.get(0).getViews()));
			opsForHash.putAll(newsKey, DBMap);//塞入缓存
			redisTemplate.expire(newsKey, 2000, time.SECONDS); //过期时间为2000秒
			json = JSON.toJSONString(DBMap);//转成json字符串
			System.out.println(opsForHash.entries(newsKey));
		}else {
			json = JSON.toJSONString(entries);
			views(newsKey);//增加新闻点击量
			model.addAttribute("message","from cache:"+json);
			return "HNews";
		}
		views(newsKey);//增加新闻点击量
		model.addAttribute("message","DB cache:"+json);
		return "HNews";
		
		
		
	}
	
	//增加新闻点击量
	private void views(String newsKey) {
		redisTemplate.opsForHash().increment(newsKey, "views", 1);
	}
	
	//使用hash和zset
	@RequestMapping("/getHNews2/{value}")
	public String getHNews2(@PathVariable("value") Long newsId,HttpServletRequest request,Model model) {
		if(newsId == null || newsId < 101) {
			model.addAttribute("message","错误的参数");
			return "HNews";
		}
		String newsKey_prefix="hnews";//新闻key的前缀
		String newsClickSet="newsclick" ;//保存新闻 点击量集合的集合名称
		String newsClickKey="news_id"+newsId;//保存新闻点击量 的成员名
		String newsKey=newsKey_prefix+newsId;  //拼凑成 一个完整的新闻key
		String json;
		HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
		Map<String, Object> entries = opsForHash.entries(newsKey); //从redis取 ,注意此时 是hash类型
		Set<String> setName = redisTemplate.opsForZSet().range(newsClickSet, 0, -1);
		if(entries == null || entries.size()<=0) {//如果木有取到
			Map<String,Object> map = new HashMap<String,Object>();
			map.put("news_id", newsId);
			List<News> newList = newsMapper.selectByMap(map); //从数据库中获取
			if(newList == null || newList.size() <= 0) {//数据库里也没取到 这里要加2分
				model.addAttribute("message","数据库里没有取到");
				return "HNews";
				//这里加入  防穿透 代码，为了代码 演示 清晰，这里暂时不加了,假设 都能取到数据
			}
			Map<String,Object> DBMap = new HashMap<String, Object>();
			DBMap.put("news_id", Long.toString(newList.get(0).getNewsId()));
			DBMap.put("news_title", newList.get(0).getNewsTitle());
			opsForHash.putAll(newsKey, DBMap);//塞入缓存,塞的是新闻数据
			redisTemplate.expire(newsKey, 2000, time.SECONDS); //过期时间为2000秒
			json = JSON.toJSONString(DBMap);//转成json字符串
			redisTemplate.opsForZSet().add(newsClickSet,newsClickKey, Long.valueOf(newList.get(0).getViews()));//塞入缓存 ,塞得是 点击量
			zSetViews(newsClickSet,newsClickKey);
			System.out.println(opsForHash.entries(newsKey));
		}else{
			json = JSON.toJSONString(entries);
			zSetViews(newsClickSet,newsClickKey);
			model.addAttribute("from cache"+json);
			return "HNews";
		}
		model.addAttribute("message","DB cache:"+json);
		return "HNews";
		
	}
	
	//这里要使用 zSet来增加了  而不是Hash
	private double zSetViews(String newsClickSet,String newsClickKey) {
		double delta = 1;
		Double score = redisTemplate.opsForZSet().incrementScore(newsClickSet, newsClickKey, delta);
		return score;
	}
	
	//使用hash和zset   增加保存缓存过期时间
	@RequestMapping("/getHNews3/{value}")
	public String getHNews3(@PathVariable("value") Long newsId, HttpServletRequest request, Model model) {
		if (newsId == null || newsId < 101) {
			model.addAttribute("message", "错误的参数");
			return "HNews";
		}
		String newsKey_prefix = "hnews";// 新闻key的前缀
		String newsClickSet = "newsclick";// 保存新闻 点击量集合的集合名称
		String newsClickKey = "news_id" + newsId;// 保存新闻点击量 的成员名
		String newsKey = newsKey_prefix + newsId; // 拼凑成 一个完整的新闻key
		String newsCacheKey="newscache";//用来保存 新闻缓存时间戳的
		String json;
		HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
		Map<String, Object> entries = opsForHash.entries(newsKey); // 从redis取 ,注意此时 是hash类型
		Set<String> setName = redisTemplate.opsForZSet().range(newsClickSet, 0, -1);
		if (entries == null || entries.size() <= 0) {// 如果木有取到
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("news_id", newsId);
			List<News> newList = newsMapper.selectByMap(map); // 从数据库中获取
			if (newList == null || newList.size() <= 0) {// 数据库里也没取到 这里要加2分
				model.addAttribute("message", "数据库里没有取到");
				return "HNews";
				// 这里加入 防穿透 代码，为了代码 演示 清晰，这里暂时不加了,假设 都能取到数据
			}
			Map<String, Object> DBMap = new HashMap<String, Object>();
			DBMap.put("news_id", Long.toString(newList.get(0).getNewsId()));
			DBMap.put("news_title", newList.get(0).getNewsTitle());
			opsForHash.putAll(newsKey, DBMap);// 塞入缓存,塞的是新闻数据
			redisTemplate.expire(newsKey, 2000, time.SECONDS); // 过期时间为2000秒
			json = JSON.toJSONString(DBMap);// 转成json字符串
			redisTemplate.opsForZSet().add(newsClickSet, newsClickKey, Long.valueOf(newList.get(0).getViews()));// 塞入缓存 ,塞得是点击量
			redisTemplate.opsForZSet().add(newsCacheKey, DateUtil.date().toString(),newsId);
			zSetViews(newsClickSet, newsClickKey);
			System.out.println(opsForHash.entries(newsKey));
		} else {
			json = JSON.toJSONString(entries);
			zSetViews(newsClickSet, newsClickKey);
			model.addAttribute("from cache" + json);
			return "HNews";
		}
		model.addAttribute("message", "DB cache:" + json);
		return "HNews";

	}
	
	
	//使用hash、zset、string   增加保存缓存过期时间
		@RequestMapping("/getHNews4/{value}")
		public String getHNews4(@PathVariable("value") Long newsId, HttpServletRequest request, Model model) {
			if (newsId == null || newsId < 101) {
				model.addAttribute("message", "错误的参数");
				return "HNews";
			}
			String newsKey_prefix = "hnews";// 新闻key的前缀
			String newsClickSet = "newsclick";// 保存新闻 点击量集合的集合名称
			String newsClickKey = "news_id" + newsId;// 保存新闻点击量 的成员名
			String newsKey = newsKey_prefix + newsId; // 拼凑成 一个完整的新闻key
			String newsCacheKey="newscache";//用来保存 新闻缓存时间戳的
			String json;
			HashOperations<String, String, Object> opsForHash = redisTemplate.opsForHash();
			Map<String, Object> entries = opsForHash.entries(newsKey); // 从redis取 ,注意此时 是hash类型
			Set<String> setName = redisTemplate.opsForZSet().range(newsClickSet, 0, -1);
			if (entries == null || entries.size() <= 0) {// 如果木有取到
				Map<String, Object> map = new HashMap<String, Object>();
				map.put("news_id", newsId);
				List<News> newList = newsMapper.selectByMap(map); // 从数据库中获取
				if (newList == null || newList.size() <= 0) {// 数据库里也没取到 这里要加2分
					model.addAttribute("message", "数据库里没有取到");
					return "HNews";
					// 这里加入 防穿透 代码，为了代码 演示 清晰，这里暂时不加了,假设 都能取到数据
				}
				Map<String, Object> DBMap = new HashMap<String, Object>();
				DBMap.put("news_id", Long.toString(newList.get(0).getNewsId()));
				DBMap.put("news_title", newList.get(0).getNewsTitle());
				opsForHash.putAll(newsKey, DBMap);// 塞入缓存,塞的是新闻数据
//				redisTemplate.expire(newsKey, 2000, time.SECONDS); // 过期时间为2000秒
				json = JSON.toJSONString(DBMap);// 转成json字符串
				redisTemplate.opsForZSet().add(newsClickSet, newsClickKey, Long.valueOf(newList.get(0).getViews()));// 塞入缓存 ,塞得是点击量
//				redisTemplate.opsForZSet().add(newsCacheKey, DateUtil.date().toString(),newsId);//使用Zset插入时间戳
				redisTemplate.opsForValue().set("news"+newsId, Long.valueOf(newsId).toString(),50,time.SECONDS);//假设存50秒
				zSetViews(newsClickSet, newsClickKey);
				System.out.println(opsForHash.entries(newsKey));
			} else {
				json = JSON.toJSONString(entries);
				zSetViews(newsClickSet, newsClickKey);
				model.addAttribute("from cache" + json);
				return "HNews";
			}
			model.addAttribute("message", "DB cache:" + json);
			return "HNews";

		}
	

}
